/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.common.entity;

import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.FrameWorkTypeEnum;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProperties;
import com.inspur.edp.web.common.JITEngineConstants;
import com.inspur.edp.web.common.constant.FrontendProjectConstant;
import com.inspur.edp.web.common.constant.WebCommonExceptionConstant;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.io.FileUtility;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 表单类型
 * 分为PC 表单和移动表单
 *
 * @author guozhiqi
 */
public enum TerminalType {
    /**
     * 个人电脑
     */
    PC {
        /**
         * PC 表单对应的文件后缀  .frm
         * @return
         */
        @Override
        public String getFormMetadataSuffix() {
            return ".frm";
        }

        @Override
        public String getFormName() {
            return "pc表单";
        }

        @Override
        public String getAppPathName() {
            return "app";
        }

        /**
         * pc 表单的webdev文件目录名称  webdev
         * @return
         */
        @Override
        public String getWebDevPathName() {
            return "webdev";
        }

        @Override
        public String getResolveBasePath(String projectPath, boolean isDynamicForm) {
            String resolveBasePath;
            if (isDynamicForm) {
                resolveBasePath = FileUtility.combineOptional(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, FrontendProjectConstant.PROJECT_GENDER_PATH_FOR_DYNAMIC_FORM);
            } else {
                resolveBasePath = FileUtility.combineOptional(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName());
            }
            return resolveBasePath;
        }

        /**
         * 获取PC 对应的publish 文件目录名称 web
         * @return
         */
        @Override
        public String getPublishPathName() {
            return "web";
        }

        @Override
        public RouteMetadata getRouteMetadata() {
            RouteMetadata routeMetadata = new RouteMetadata();
            routeMetadata.setCode("predefinePageflow");
            routeMetadata.setType("PageFlowMetadata");
            routeMetadata.setFileSuffix(".pf");
            routeMetadata.setFileName(routeMetadata.getCode() + routeMetadata.getFileSuffix());
            return routeMetadata;
        }

        @Override
        public String getMetadataType() {
            return "Form";
        }

        @Override
        public String getFrameworkType() {
            return "angular";
        }

    },
    /**
     * 移动设备
     */
    MOBILE {
        /**
         * 移动表单对应的文件后缀  .mfrm
         *
         * @return
         */
        @Override
        public String getFormMetadataSuffix() {
            return ".mfrm";
        }

        @Override
        public String getFormName() {
            return "移动表单";
        }

        /**
         * 移动表单生成位置  mobileapp
         * @return
         */
        @Override
        public String getAppPathName() {
            return "mobileapp";
        }

        /**
         * 移动表单对应的webdev目录名称  mobiledev
         * @return
         */
        @Override
        public String getWebDevPathName() {
            return "mobiledev";
        }


        @Override
        public String getResolveBasePath(String projectPath, boolean isDynamicForm) {
            return FileUtility.combine(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName());
        }

        /**
         * 获取移动表单对应的publish 目录路径名称 mob
         * @return
         */
        @Override
        public String getPublishPathName() {
            return "mob";
        }

        @Override
        public RouteMetadata getRouteMetadata() {
            RouteMetadata routeMetadata = new RouteMetadata();
            routeMetadata.setCode("predefineMobilePageflow");
            routeMetadata.setType("MobilePageFlowMetadata");
            routeMetadata.setFileSuffix(".mpf");
            routeMetadata.setFileName(routeMetadata.getCode() + routeMetadata.getFileSuffix());
            return routeMetadata;
        }

        /**
         * 获取移动关联的元数据类型  MobileForm
         * @return
         */
        @Override
        public String getMetadataType() {
            return "MobileForm";
        }

        @Override
        public String getFrameworkType() {
            return "vue";
        }
    },
    VUE {
        @Override
        public String getFormMetadataSuffix() {
            return ".frm";
        }

        @Override
        public String getFormName() {
            return "pc表单";
        }

        @Override
        public String getAppPathName() {
            return "vueapp";
        }

        /**
         * pc 表单的webdev文件目录名称  webdev
         * @return
         */
        @Override
        public String getWebDevPathName() {
            return "vuewebdev";
        }

        @Override
        public String getResolveBasePath(String projectPath, boolean isDynamicForm) {
            String resolveBasePath;
            if (isDynamicForm) {
                resolveBasePath = FileUtility.combineOptional(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, FrontendProjectConstant.PROJECT_GENDER_PATH_FOR_DYNAMIC_FORM);
            } else {
                resolveBasePath = FileUtility.combineOptional(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName());
            }
            return resolveBasePath;
        }

        /**
         * 获取PC 对应的publish 文件目录名称 web
         * @return
         */
        @Override
        public String getPublishPathName() {
            return "web";
        }

        @Override
        public RouteMetadata getRouteMetadata() {
            RouteMetadata routeMetadata = new RouteMetadata();
            routeMetadata.setCode("predefinePageflow");
            routeMetadata.setType("PageFlowMetadata");
            routeMetadata.setFileSuffix(".pf");
            routeMetadata.setFileName(routeMetadata.getCode() + routeMetadata.getFileSuffix());
            return routeMetadata;
        }

        @Override
        public String getMetadataType() {
            return "Form";
        }

        @Override
        public String getFrameworkType() {
            return "vue";
        }


    };


    /**
     * 获取对应类型的表单元数据的后缀格式
     *
     * @return
     */
    public abstract String getFormMetadataSuffix();

    /**
     * 获取表单类型对应的name参数值
     *
     * @return
     */
    public abstract String getFormName();

    /**
     * 获取对应的app路径名称
     *
     * @return
     */
    public abstract String getAppPathName();

    /**
     * 获取关联的webdev 目录路径名称
     *
     * @return
     */
    public abstract String getWebDevPathName();


    /**
     * 根据terminalType执行不同的supplier
     *
     * @param terminalType
     * @param executeWithPCSupplier
     * @param executeWithMobileSupplier
     * @return
     */
    public static String getCustomExecuteResult(TerminalType terminalType, Supplier<String> executeWithPCSupplier, Supplier<String> executeWithMobileSupplier) {
        if (terminalType == TerminalType.MOBILE) {
            if (executeWithMobileSupplier == null) {
                throw new WebCustomException("executeWithMobileSupplier 不能为空");
            }
            return executeWithMobileSupplier.get();
        }
        if (executeWithPCSupplier == null) {
            throw new WebCustomException("executeWithPCSupplier不能为空");
        }
        return executeWithPCSupplier.get();
    }

    /**
     * 根据元数据获取终端类型
     * <p>
     * 此方法旨在通过检查元数据的类型和属性来确定终端类型
     * 它首先检查元数据的类型，然后根据类型进一步检查属性以确定终端类型
     *
     * @param formMd 元数据对象，包含表单的元数据信息
     * @return 返回对应的终端类型如果无法确定终端类型，则返回null
     */
    public static TerminalType getTerminalTypeByMetadata(GspMetadata formMd) {
        // 获取元数据的头部信息
        MetadataHeader header = formMd.getHeader();
        // 从头部信息中提取元数据类型
        String mdType = header.getType();

        // 根据元数据类型进行处理
        switch (mdType) {
            case "Form":
                // 获取元数据的属性信息
                MetadataProperties properties = formMd.getProperties();
                // 初始化框架类型枚举变量
                FrameWorkTypeEnum frameWorkTypeEnum = null;
                // 检查属性是否存在，并获取框架类型
                if (properties == null) {
                    GspMetadata metadata = MetadataUtility.getInstance().getMetadataWithRuntime(formMd.getHeader().getId());
                    if (metadata != null) {
                        MetadataProperties propertyInContent = metadata.getProperties();
                        if (propertyInContent != null && FrameWorkTypeEnum.Vue.equals(propertyInContent.getFramework())) {
                            return TerminalType.VUE;
                        }
                    }
                }
                if (properties != null) {
                    frameWorkTypeEnum = properties.getFramework();
                }
                // 根据框架类型确定终端类型
                if (frameWorkTypeEnum == FrameWorkTypeEnum.Vue) {
                    return TerminalType.VUE;
                }
                return TerminalType.PC;
            case "MobileForm":
                // 直接返回移动终端类型
                return TerminalType.MOBILE;
            default:
                // 默认情况下返回null，表示无法确定终端类型
                return null;
        }
    }


    /**
     * 获取指定类型的resolve 基础路径
     * PC  projectPath/src/webdev
     * PC 解析表单 projectPath/src/appfordynamic
     * Mobile projectPath/src/mobiledev
     *
     * @param projectPath
     * @param isDynamicForm
     * @return
     */
    public abstract String getResolveBasePath(String projectPath, boolean isDynamicForm);

    /**
     * 获取对应表单类型的publish 目录名称
     *
     * @return
     */
    public abstract String getPublishPathName();

    /**
     * 获取对应的页面流定义
     *
     * @return
     */
    public abstract RouteMetadata getRouteMetadata();

    /**
     * 获取关联得元数据类型
     *
     * @return
     */
    public abstract String getMetadataType();

    /**
     * 获取对应的框架类型 主要为Angular  或  Vue
     *
     * @return
     */
    public abstract String getFrameworkType();

    /**
     * 是否 PC
     *
     * @param metadataType
     * @return
     */
    public static boolean isPC(String metadataType) {
        return TerminalType.PC.getMetadataType().equals(metadataType);
    }

    /**
     * 是否 PC
     *
     * @param terminalType
     * @return
     */
    public static boolean isPC(TerminalType terminalType) {
        return TerminalType.PC == terminalType;
    }

    /**
     * 是否 mobile
     *
     * @param terminalType
     * @return
     */
    public static boolean isMobile(TerminalType terminalType) {
        return TerminalType.MOBILE == terminalType;
    }

    /**
     * 是否 Mobile
     *
     * @param metadataType
     * @return
     */
    public static boolean isMobile(String metadataType) {
        return TerminalType.MOBILE.getMetadataType().equals(metadataType);
    }

    /**
     * 是否 PC 或 Mobile
     *
     * @param metadataType
     * @return
     */
    public static boolean isPCOrMobile(String metadataType) {
        return isPC(metadataType) || isMobile(metadataType);
    }


    /**
     * 针对 pc、mobile 循环执行其参数
     * 不会捕获异常
     *
     * @param consumer
     */
    public static void rescure(Consumer<TerminalType> consumer) {
        if (consumer == null) {
            return;
        }

        consumer.accept(TerminalType.PC);
        consumer.accept(TerminalType.MOBILE);
        consumer.accept(TerminalType.VUE);
    }

    /**
     * 获取表单相对路径，相对于metadata目录
     * 获取PC 相对于metadata的目录路径，类似于  src/webdev/services 或 src/mobiledev/services
     *
     * @return
     */
    public String getServiceRelativePath() {
        return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName(), FrontendProjectConstant.COMMAND_SERVICES_PRODUCT_PATH);
    }

    /**
     * 获取styles相对路径，相对于metadata目录
     * 相对于metadata的目录路径，类似于  src/webdev/styles 或 src/mobiledev/styles
     *
     * @return
     */
    public String getStyleRelativePath() {
        return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName(), FrontendProjectConstant.STYLE_PRODUCT_PATH);
    }


    /**
     * 获取表单 相对路径，相对于metadata目录
     *
     * @param isSingleDynamicForm
     * @return
     */
    public String getServiceRelativePath(boolean isSingleDynamicForm) {
        // 仅在PC 表单下支持解析预览动作
        if (isSingleDynamicForm && this == TerminalType.PC) {
            return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, FrontendProjectConstant.COMMAND_SERVICES_PRODUCT_PATH);
        }
        return this.getServiceRelativePath();
    }

    /**
     * 获取表单html模板
     *
     * @param isSingleDynamicForm
     * @return
     */
    public String getHtmlTemplateRelativePath(boolean isSingleDynamicForm) {
        // 仅在PC 表单下支持解析预览动作
        if (isSingleDynamicForm && this == TerminalType.PC) {
            return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, FrontendProjectConstant.HtmlTemplate_PRODUCT_PATH);
        }
        return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName(), FrontendProjectConstant.HtmlTemplate_PRODUCT_PATH);
    }

    /**
     * 获取工程目录中待部署脚本的路径，类似于 src/app/dist-rollup 或 src/mobileapp/dist-rollup
     *
     * @return
     */
    public String getDeployableProjectRelativePath() {
        return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getAppPathName(), JITEngineConstants.DistRollupPathName);
    }

    /**
     * 获取工程目录中待部署脚本的路径，类似于 src/app/dist-rollup 或 src/mobileapp/dist-rollup
     *
     * @return
     */
    public String getDeployableProjectRelativePath(boolean isJieXiForm) {
        if (isJieXiForm && this == TerminalType.PC) {
            return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, "dynamicform");
        }
        return this.getDeployableProjectRelativePath();
    }

    /**
     * 获取i18n 资源文件在webdev中的部署目录，类似于 src/webdev/i18n 或 src/mobiledev/i18n
     *
     * @return
     */
    public String getWebDevI18nRelativePath() {
        return FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, this.getWebDevPathName(), FrontendProjectConstant.I18N_SRESOURCE_PATH);
    }

    /**
     * 获取定义的表单类型列表
     * static 定义  不通过具体的枚举值获取
     *
     * @return
     */
    public static List<String> getAllTypeSuffixList() {
        List<String> suffixList = new ArrayList<>();
        TerminalType[] arrTerminalType = TerminalType.values();
        for (TerminalType terminalTypeItem : arrTerminalType) {
            suffixList.add(terminalTypeItem.getFormMetadataSuffix());
        }
        return suffixList;
    }

    /**
     * 根据源数据类型转换成对应的元数据类型
     *
     * @param sourceMetadataType
     * @return
     */
    public static TerminalType fromMetadataType(String sourceMetadataType) {
        if (TerminalType.PC.getMetadataType().equals(sourceMetadataType)) {
            return TerminalType.PC;
        } else if (TerminalType.MOBILE.getMetadataType().equals(sourceMetadataType)) {
            return TerminalType.MOBILE;
        } else {
            throw new WebCustomException(WebCommonExceptionConstant.WEB_COMMON_ERROR_0003, new String[]{sourceMetadataType});
        }
    }

    /**
     * 关联页面流常量定义
     */
    @Data
    public static class RouteMetadata {
        /**
         * 关联页面流code
         */
        private String code;
        private String fileName;
        private String type;
        private String fileSuffix;

    }
}

